package com.enpronomics.pcall;

import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import android.content.Context;
import android.location.Criteria;
import android.location.GpsSatellite;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;

public class GetLocation {
	
	private Context context;
	private LocationManager myLocationManager;
	private Location bestLocation = null;
	private LocationResult locationResult;
	
	private boolean gps_enabled = false;
	private boolean network_enabled = false;
	
	private int counts = 0;
	private int sat_count = 0;
	private int delayTime=500;
	private int min_gps_sat_count = 3;
	
	private void locationGot(){
		new Handler().post(new Runnable() {
			@Override
			public void run() {
				locationResult.locationGot(bestLocation);
			}
		});
		
	}
	
	public GetLocation(Context c, LocationResult result) {
		context=c;
		locationResult=result;
		if (checkConnection()) {
			
			myLocationManager.addGpsStatusListener(gpsStatusListener);
			if (gps_enabled) {
				myLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
			}
			if (network_enabled) {
				myLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,locationListener);
			}
			
			new Timer().schedule(checkLocation, delayTime,delayTime);
		}else locationGot();
	}
	
	private TimerTask checkLocation=new TimerTask() {
		public void run() {
			boolean stop = false;
			counts++;
			if (counts > 60) stop = true;// if timeout (1 min) exceeded, stop tying
//			Location currentLocation=getLocation(context);
//			if(isBetterLocation(currentLocation, bestLocation))bestLocation=currentLocation;
			bestLocation =getLocation(context);

			if (stop == true || needToStop()) {
				myLocationManager.removeUpdates(locationListener);
				try{myLocationManager.removeUpdates(locationListener);}catch (Exception e) {}
				myLocationManager.removeGpsStatusListener(gpsStatusListener);
				cancel();stop=false;gps_enabled=false;network_enabled=false;
				locationGot();
			}
		}
	};
	private Boolean needToStop() {
		if(!gps_enabled && !network_enabled)return true;
		if (counts < 3) {
			return false;
		}
		if (sat_count < min_gps_sat_count) {
			if (counts >= 40 && sat_count >= 3) {
				return true;
			}
			return false;
		} else return true;
	}
	private boolean checkConnection() {
		myLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
		try {
			gps_enabled = myLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
		} catch (Exception ex) {}
		
		try {
			network_enabled = myLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
		} catch (Exception ex) {}
		return (gps_enabled || network_enabled);
	}
	
	private static Location getLocation(Context context) {
		try {
			LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
			Criteria criteria = new Criteria();
			criteria.setAccuracy(Criteria.ACCURACY_FINE);
			criteria.setAltitudeRequired(false);
			criteria.setBearingRequired(false);
			criteria.setCostAllowed(true);
			String strLocationProvider = lm.getBestProvider(criteria, true);
			Location location = lm.getLastKnownLocation(strLocationProvider);
			if (location != null) {
				return location;
			}
			return null;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	private GpsStatus.Listener gpsStatusListener = new GpsStatus.Listener() {
		public void onGpsStatusChanged(int event) {

			if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) {
				try {
					// Check number of satellites in list to determine fix state
					GpsStatus status = myLocationManager.getGpsStatus(null);
					Iterable<GpsSatellite> satellites = status.getSatellites();

					sat_count = 0;

					Iterator<GpsSatellite> satI = satellites.iterator();
					while (satI.hasNext()) {
						GpsSatellite satellite = satI.next();
						System.out.println("Satellite: snr="
								+ satellite.getSnr() + ", elevation="
								+ satellite.getElevation());
						sat_count++;
					}
				} catch (Exception e) {
					e.printStackTrace();
					sat_count = min_gps_sat_count + 1;
				}

				System.out.println("#### sat_count = " + sat_count);
			}
		}
	};
	private LocationListener locationListener=new LocationListener() {	
		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {}
		@Override
		public void onProviderEnabled(String provider) {}
		@Override
		public void onProviderDisabled(String provider) {}
		@Override
		public void onLocationChanged(Location location) {}
	};
	
	private static final int TWO_MINUTES = 1000 * 60 * 2;
	protected boolean isBetterLocation(Location location,
			Location currentBestLocation) {
		if (currentBestLocation == null) {
			// A new location is always better than no location
			return true;
		}

		// Check whether the new location fix is newer or older
		long timeDelta = location.getTime() - currentBestLocation.getTime();
		boolean isSignificantlyNewer = timeDelta > TWO_MINUTES;
		boolean isSignificantlyOlder = timeDelta < -TWO_MINUTES;
		boolean isNewer = timeDelta > 0;

		// If it's been more than two minutes since the current location, use
		// the new location
		// because the user has likely moved
		if (isSignificantlyNewer) {
			return true;
			// If the new location is more than two minutes older, it must be
			// worse
		} else if (isSignificantlyOlder) {
			return false;
		}

		// Check whether the new location fix is more or less accurate
		int accuracyDelta = (int) (location.getAccuracy() - currentBestLocation
				.getAccuracy());
		boolean isLessAccurate = accuracyDelta > 0;
		boolean isMoreAccurate = accuracyDelta < 0;
		boolean isSignificantlyLessAccurate = accuracyDelta > 200;

		// Check if the old and new location are from the same provider
		boolean isFromSameProvider = isSameProvider(location.getProvider(),
				currentBestLocation.getProvider());

		// Determine location quality using a combination of timeliness and
		// accuracy
		if (isMoreAccurate) {
			return true;
		} else if (isNewer && !isLessAccurate) {
			return true;
		} else if (isNewer && !isSignificantlyLessAccurate
				&& isFromSameProvider) {
			return true;
		}
		return false;
	}

	/** Checks whether two providers are the same */
	private boolean isSameProvider(String provider1, String provider2) {
		if (provider1 == null) {
			return provider2 == null;
		}
		return provider1.equals(provider2);
	}
}
